'use strict'
const fs = require("fs"),
    iconv = require('iconv-lite'),
    axios = require('axios').default;
const schedule = require("node-schedule");
let Book = function (config) {
    /**
     * 载入配置
     */
    this.config = config;
    this.ss = '';
    /**
     * get请求通用
     */
    this.requestGet = function (url) {
        return new Promise(function (resolve, reject) {
            axios.get(url, {
                responseType: "arraybuffer"
            }).then(function (response) {
                if (response.data) {
                    resolve(response.data);
                } else {
                    reject();
                }
            });
        });
    }
    /**
     * post请求通用
     */
    this.requestPost = function (url, data) {
        return new Promise(function (resolve, reject) {
            axios.post(url, data, {
                responseType: "arraybuffer"
            }).then(function (response) {
                if (response.data) {
                    resolve(response.data);
                } else {
                    reject();
                }
            });
        });
    }
    /**
     * 返回通用消息格式
     */
    this.send = function (code, data, msg = '操作成功') {
        return {
            code: code,
            data: data,
            msg: msg
        }
    }
    /**
     * 小说类型转换及通用返回
     */
    this.getType = function (name) {
        let _name = "其它"
        if (name.indexOf("都市") > -1 || name.indexOf("现代") > -1 || name.indexOf("言情") > -1 || name.indexOf("青春") > -1) {
            _name = "都市";
        }
        if (name.indexOf("玄幻") > -1) {
            _name = "玄幻";
        }
        if (name.indexOf("奇幻") > -1 || name.indexOf("仙侠") > -1 || name.indexOf("修真") > -1 || name.indexOf("武侠") > -1) {
            _name = "奇幻";
        }
        if (name.indexOf("历史") > -1) {
            _name = "历史";
        }
        if (name.indexOf("科幻") > -1) {
            _name = "科幻";
        }
        if (name.indexOf("军事") > -1) {
            _name = "军事";
        }
        if (name.indexOf("游戏") > -1 || name.indexOf("网游") > -1) {
            _name = "游戏";
        }
        return _name
    }

    let ssURL = ()=>{
        this.requestGet("https://www.xsxs520.cc/js/common.js").then(data => {
            let html = iconv.decode(data, "gbk");
            this.ss = html.substr(html.indexOf("form action=")+15);
            this.ss = this.ss.substr(0,this.ss.indexOf(".php"));
        })
    }
  

    schedule.scheduleJob({ hour: 2, minute: 0 }, function () {
        console.log("更新地址任务:" + new Date());
        ssURL()
    });
    ssURL()
}
/**
 * API文档
 */
Book.prototype.API = function (req, res) {
    res.setHeader('Content-type', 'text/html');
    res.send(fs.readFileSync('api.html').toString())
}
/**
 * 图片代理
 */
Book.prototype.PUBLIC = function (req, res) {
    this.requestGet(this.config[req.params.key].host + req.params['0']).then(data => {
        res.setHeader('Content-type', "image/jpeg");
        res.send(data);
    })
}
/**
 * 获取热门数据（百度top）
 * 这种接口就固定，能用上就用，用不上就算了
 */
Book.prototype.HOT = function (req, res) {
    let category = "全部类型"
    if (req.query.category) {
        category = req.query.category
    }
    this.requestGet("https://top.baidu.com/board?platform=pc&tab=novel&tag={\"category\":\"" + category + "\"}").then(data => {
        let regExp = /\[{"appUrl"([\d\D]+)}\],"more/g;
        let html = regExp.exec(data.toString())[0];
        html = html.replace(",\"more", "");
        let bookData = JSON.parse(html);
        let books = [];
        bookData.forEach(item => {
            books.push({
                img: item.img,
                desc: item.desc,
                hot: item.hotScore,
                name: item.word,
                type: this.getType(item.show[1].replace("类型：", "")),
                author: item.show[0].replace("作者：", "")
            })
        })
        res.send(this.send(1, books))
    }).catch(() => {
        res.send(this.send(0, null, "解析失败，请联系管理员"))
    })
}

/**
 * 聚合去重搜索
 * 异步处理，尽可能节约转义时间
 */
Book.prototype.SEARCH = function (req, res) {
    if (!req.query.keyword) {
        res.send(this.send(0, null, "请输入搜索书名"))
        return
    }
    //执行记数
    let ajaxIndex = 0, list = [];
    //增加,聚合去重
    let addlist = (row) => {
        //检查是否存在
        var index = list.findIndex(item => item.name === row.name);
        if (index > -1) {
            //判断各数据是否存在
            Object.keys(list[index]).forEach(x=>{
                // 如果空，则使用row的
                if(!list[index][x]){
                    list[index][x] = row[x];
                }
            })
            //存在,增加一个来源
            list[index].book.push(row.book);
        } else {
            //不存在，新增加
            list.push({
                img: row.img,//图片
                desc: row.desc,//简介
                name: row.name,//书名
                type: row.type,//类型
                author: row.author,//作者
                book: [row.book]//来源
            })
        }
    }
    //返回
    let success = () => {
        if (ajaxIndex === Object.keys(this.config).length) {
            res.send(this.send(1, list))
        }
    }
    //解析
    let parseData = (key, model, data) => {
        let html = iconv.decode(data, model.charset),
            regExp = new RegExp(model.search.regExp, "g"),
            arr;
        while (arr = regExp.exec(html)) {
            addlist(
                {
                    img: "/public/" + key + arr[model.search.img],
                    desc: arr[model.search.desc],
                    name: arr[model.search.name],
                    type: this.getType(arr[model.search.type]),
                    author: arr[model.search.author],
                    book: {
                        name: model.name,
                        url: "/book/" + key + arr[model.search.url],
                        new: arr[model.search.new],
                        newurl: "/book/read/" + key + arr[model.search.newurl],
                    }
                }
            )
        }
    }
    //解析config
    Object.keys(this.config).forEach(key => {
        let model = this.config[key];
        //区分搜索请求方式
        if (model.search.method === "get") {
            this.requestGet(model.search.host.replace("[keyword]", req.query.keyword).replace("[ss]", this.ss)).then(data => {
                parseData(key, model, data);
            }).finally(() => {
                //不管成功失败都要计数
                ajaxIndex++;
                success();
            })
        } else {
            let _post = model.search.post;
            //反序列化赋值替换
            Object.keys(_post).forEach(params => {
                _post[params] = _post[params].replace("[keyword]", req.query.keyword).replace("[ss]", this.ss)
            })
            this.requestPost(model.search.host, _post).then(data => {
                parseData(key, model, data);
            }).finally(() => {
                //不管成功失败都要计数
                ajaxIndex++;
                success();
            })
        }
    })
}


/**
 * 根据小说名获取不同来源站的地址
 */
Book.prototype.BOOK = function (req, res) {
    if (!req.query.name) {
        res.send(this.send(0, null, "请输入书名"))
        return
    }
    //执行记数
    let ajaxIndex = 0, list = [];
    //返回
    let success = () => {
        if (ajaxIndex === Object.keys(this.config).length) {
            res.send(this.send(1, list))
        }
    }
    //解析config
    Object.keys(this.config).forEach(key => {
        let model = this.config[key];
        this.requestGet(model.search.host.replace("[keyword]", req.query.name).replace("[ss]", this.ss)).then(data => {
            let html = iconv.decode(data, model.charset),
                regExp = new RegExp(model.search.regExp, "g"),
                arr;
            while (arr = regExp.exec(html)) {
                if (req.query.name === arr[model.search.name]) {
                    list.push({
                        name: model.name,
                        url: "/book/" + key + arr[model.search.url],
                        new: arr[model.search.new],
                        newurl: "/book/read/" + key + arr[model.search.newurl],
                    })
                }
            }
        }).finally(() => {
            //不管成功失败都要计数
            ajaxIndex++;
            success();
        })
    })
}
/**
 * 获取小说详情
 */
Book.prototype.BOOKREAD = function (req, res) {
    let model = this.config[req.params.key];
    this.requestGet(model.host + req.params['0']).then(data => {
        let html = iconv.decode(data, model.charset);
        let regName = new RegExp(model.book.name.regExp, "g"),
            regDesc = new RegExp(model.book.desc.regExp, "g"),
            regType = new RegExp(model.book.type.regExp, "g"),
            regAuthor = new RegExp(model.book.author.regExp, "g"),
            regImg = new RegExp(model.book.img.regExp, "g"),
            regList = new RegExp(model.book.list.regExp, "g"),
            _list = [],
            arr;
        while (arr = regList.exec(html)) {
            _list.push({
                name: arr[model.book.list.name],
                url: "/book/read/" + req.params.key + arr[model.book.list.url],
            })
        }
        let book = {
            img: "/public/" + req.params.key + regImg.exec(html)[model.book.img.value],
            desc: regDesc.exec(html)[model.book.desc.value],
            name: regName.exec(html)[model.book.name.value],
            type: this.getType(regType.exec(html)[model.book.type.value]),
            author: regAuthor.exec(html)[model.book.author.value],
            list: _list
        }
        res.send(this.send(1, book));
    }).catch((data) => {
        res.send(this.send(0, null, "解析失败，请联系管理员"));
    })
}

/**
 * 获取章节内容
 */
Book.prototype.BOOKREADINFO = function (req, res) {
    let model = this.config[req.params.key];
    this.requestGet(model.host + req.params['0']).then(data => {
        let html = iconv.decode(data, model.charset);
        let regName = new RegExp(model.read.name.regExp, "g"),
            regText = new RegExp(model.read.text.regExp, "g"),
            regNext = new RegExp(model.read.next.regExp, "g"),
            regUp = new RegExp(model.read.up.regExp, "g"),
            name = regName.exec(html)[model.read.name.value],
            text = regText.exec(html)[model.read.text.value],
            next = regNext.exec(html)[model.read.next.value],
            up = regUp.exec(html)[model.read.up.value],
            book = {
                name: name,
                text: text,
                next: "/book/" + (next.indexOf(".html") > -1 ? "read/" : "") + req.params.key + next,
                up: "/book/" + (up.indexOf(".html") > -1 ? "read/" : "") + req.params.key + up,
            };
        res.send(this.send(1, book));
    }).catch(() => {
        res.send(this.send(0, null, "解析失败，请联系管理员"));
    })
}

module.exports = Book;